const express = require('express')
const moment = require('moment')
const md5 = require('nodejs-md5')
const compression = require('compression')
const path = require('path')
const cors = require('cors')
const fs = require('fs')
const multer = require('multer')
const os = require('os')
const app = express()
const request = require('request')
const crypto = require('crypto')
const OSS = require('ali-oss')
const { v4: uuidv4 } = require('uuid')
const Autoplan = require('./autoplan')
const zlib = require('zlib')
const { getUGM } = require('./handleData')

//同步读取密钥和签名证书
// const options = {
//   key: fs.readFileSync('./key/ca.key'),
//   cert: fs.readFileSync('./key/ca.crt')
// }

// 创建upload文件夹
const uploadFolder = './upload/'
let current_time = null
let client

const log = ({ url, body }) => {
  current_time = Date.now()
  const day = moment(current_time).format('YYYY-MM-DD--HH:mm:ss')
  switch (url) {
    case '/save_data':
      console.log('\x1b[33m%s\x1b[0m', '\n' + day, `接收到${url}请求`, '参数为:', body.ugmId)
      break
    case '/clone_ugm':
      console.log('\x1b[33m%s\x1b[0m', '\n' + day, `接收到${url}请求`, '参数为:', body.originId)
      break
    case '/put_ugm_to_ail':
      console.log('\x1b[33m%s\x1b[0m', '\n' + day, `接收到${url}请求`, '参数为:', body.targetId)
      break
    default:
      console.log('\x1b[33m%s\x1b[0m', '\n' + day, `接收到${url}请求`, '参数为:', body)
  }
}

const logRes = arg => {
  const { res, res_code, e, mes } = arg
  current_time = Date.now()
  const day = moment(current_time).format('YYYY-MM-DD--HH:mm:ss')
  if (res_code > -1) {
    console.log('\x1b[33m%s\x1b[0m', '\n' + day, `res_code=${res_code}`)
  } else {
    console.log('\x1b[33m%s\x1b[0m', '\n' + day, `res_code=${res_code}`, `e=${e}`, `mes=${mes}`)
  }
  res.send({ ...arg, res: null })
}

const getMD5 = str => {
  const hash = crypto.createHash('md5')
  hash.update(str)
  const targetData = hash.digest('hex')
  // let byte2String = ''
  // for (let i = 0; i < targetData.Length; i++) {
  //   byte2String += targetData[i].toString('x2')
  // }
  return targetData
}

const createTOKEN = () => {
  const appid = 'VQsqfKeSPIzdN0my'
  const deviceId = os.hostname() //主机名
  const _params = ''
  const ts = Date.now() - new Date('1970-01-01 00:00:00:00')
  const timestamp = ts.toString()
  const str1 = appid + deviceId + _params + timestamp
  const str2 = str1 + 'qORS*XVbQAjHryqKPve^hd^iWFx&P^cY'
  const token = getMD5(str2)
  return [timestamp, token]
}
// const AgentKeepalive = require('agentkeepalive')
// const agent = new AgentKeepalive({
//   maxSockets: 3
// })
const getAliyunKey = () =>
  new Promise((resolve, reject) => {
    const [timestamp, token] = createTOKEN()
    const url = 'https://api.zhihuiliang.com/open/storage/aliyun/getAccessToken'
    request(
      {
        url: url,
        method: 'POST',
        headers: {
          'content-type': 'application/x-www-form-urlencoded'
        },
        form: {
          appId: 'VQsqfKeSPIzdN0my',
          deviceId: os.hostname(),
          params: '',
          token,
          timestamp
        }
      },
      function (e, response, body) {
        if (!e && response.statusCode === 200) {
          const { accessKeyId, accessKeySecret, securityToken } = JSON.parse(JSON.parse(body).data)
          if (!client) {
            client = new OSS({
              endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
              accessKeyId: accessKeyId,
              accessKeySecret: accessKeySecret,
              refreshSTSToken: async () => {
                const { accessKeyId, accessKeySecret, securityToken } = await getAliyunKey()
                // 向您搭建的STS服务获取临时访问凭证。
                return {
                  accessKeyId: accessKeyId,
                  accessKeySecret: accessKeySecret,
                  stsToken: securityToken
                }
              },
              stsToken: securityToken,
              timeout: 30 * 60 * 1000,
              // agent: agent,
              internal: false,
              refreshSTSTokenInterval: 1000 * 1800,
              bucket: 'unre-cad'
            })
          }
          resolve({ accessKeyId, accessKeySecret, securityToken })
        } else {
          reject(e)
        }
      }
    )
  })

getAliyunKey()

const gzipSync = data => zlib.gzipSync(Buffer.from(JSON.stringify(data)))

const unzipSync = res => JSON.parse(zlib.unzipSync(res.content).toString())

const getDataFromAil = async getName => {
  const type = getName.substring(0, 3)
  if (type === 'ugm') {
    let res = null
    let ugm = null
    try {
      res = await client.get(`${getName}.gz`)
      ugm = unzipSync(res)
    } catch (e) {
      res = await client.get(getName)
      ugm = JSON.parse(res.content.toString())
    }
    if (ugm && ugm.data && ugm.data.docs) {
      const docs = ugm.data.docs
      let sign = false
      for (const key in docs) {
        if (docs[key].id !== key) {
          sign = true
          break
        }
      }
      if (sign) {
        ugm.data.docs = {}
        ugm.bim.docs = {}
        for (const key in ugm.data.cols) {
          ugm.data.cols[key].forEach(doc => {
            ugm.data.docs[doc.id] = doc
          })
        }
        for (const key in ugm.bim.cols) {
          ugm.bim.cols[key].forEach(doc => {
            ugm.bim.docs[doc.id] = doc
          })
        }
      }
    }
    return ugm
  } else {
    const result = await client.get(getName)
    return result
  }
}

const putDataToAil = async (putName, data) => {
  if (Object.keys(data).length < 2) {
    return null
  }
  if (!data.boundingbox || !data.boundingbox.length) {
    data = getUGM({ architecture: data })
  }
  data = addCurrentTimeToUGM(data)
  const buf = gzipSync(data)
  const res = await client.put(`${putName}.gz`, buf)
  return res
}

const addCurrentTimeToUGM = ugm => {
  if (ugm.current_time) return ugm
  if (!ugm.data.cols.timestamp || !ugm.data.cols.timestamp.length) {
    const timestamp = { id: uuidv4(), timestamp: Date.now().toString(), definition: 'timestamp' }
    ugm.data.cols.timestamp = [timestamp]
    ugm.data.docs[timestamp.id] = timestamp
    ugm.current_time = timestamp.timestamp
  } else {
    ugm.current_time = ugm.timestamp[0].timestamp
  }
  return ugm
}

const createFolder = function (folder) {
  try {
    fs.accessSync(folder)
  } catch (e) {
    fs.mkdirSync(folder)
  }
}

createFolder(uploadFolder)

// 通过 filename 属性定制
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, uploadFolder) // 保存的路径，备注：需要自己创建
  },
  filename: function (req, file, cb) {
    // 将保存文件名设置为 字段名 + 时间戳，比如 logo-1478521468943
    const { fieldname, originalname } = file
    if (fieldname === 'ugm') {
      cb(null, fieldname + '-' + Date.now() + '.json')
    } else if (fieldname === 'pdf') {
      cb(null, fieldname + '-' + Date.now() + '.pdf')
    } else if (fieldname === 'dwg') {
      cb(null, fieldname + '-' + Date.now() + '.dwg')
    } else if (fieldname === 'data') {
      cb(null, path.basename(originalname, path.extname(originalname)) + '-' + Date.now() + path.extname(originalname))
    }
  }
})

const upload = multer({ storage: storage })
const options = {
  immutable: true,
  lastModified: true,
  maxAge: '1d'
}

function shouldCompress(req, res) {
  // if (req.url !== '/get_data' && req.url !== '/get_data_from_ail') {
  //   return false
  // }
  return compression.filter(req, res)
}

// const server = app.listen(app.get('port'), function() {
//   console.log('Express server listening on port ' + server.address().port);
// });
// server.setTimeout(30 * 60 * 1000);
app.use(compression({ filter: shouldCompress, level: 9 }))
app.use(express.json({ limit: '100mb' }))
app.use(cors())
app.use(express.urlencoded({ limit: '100mb', extended: true }))
app.use(express.static(path.join(__dirname, 'dist'), options))
app.use(function (req, res, next) {
  res.setTimeout(60 * 1000 * 30, function () {
    return res.status(408).send('请求超时')
  })
  next()
})
app.use('/', (request, response, next) => {
  console.log('中间件')
  log(request)
  next()
})
app.get('/', (req, res) => {
  const options = {
    root: __dirname,
    headers: {
      'Content-Type': 'text/html'
    }
  }
  res.sendFile('./dist/index.html', options, function (e) {
    if (e) {
      console.log('Sent failed:', 'index.html' + e)
    } else {
      console.log('Sent sucess:', 'index.html')
    }
  })
})

app.post('/repair', async (req, res) => {
  // log(req)
  const { taskId } = req.body
  try {
    const getName = `ugmJson/${taskId}_graph.json`
    const ugm = await getDataFromAil(getName)
    const ugmPath = `./upload/${taskId}_graph.json`
    fs.writeFileSync(ugmPath, JSON.stringify(ugm))
    logRes({ res, res_code: 0 })
  } catch (e) {
    logRes({ res, res_code: -1 })
  }
})

/**
 * LAST_UPDATE: 2021.06.22
 * CAD插件上传ugm.json文件使用
 * params:{
 *    ugm : xxx.json,
 *    md5 : xxx (不能加引号)
 * }
 */
app.post('/upload_data', upload.single('ugm'), function (req, res) {
  // log(req)
  if (!req.file) {
    logRes({ res, res_code: -1 })
  } else {
    md5.file.quiet('./upload/' + req.file.filename, async (err, md5_code) => {
      if (err) {
        console.log(err)
      } else {
        console.log(`md5     =${req.body.md5}`)
        console.log(`md5_code=${md5_code}`)
        const oldPath = uploadFolder + req.file.filename
        if (md5_code === req.body.md5) {
          console.log('MD5校验完成')
          try {
            const { taskId } = req.body
            const architecture = JSON.parse(fs.readFileSync(oldPath, 'utf-8'))
            if (architecture && architecture.StructureDottedLine) {
              const point = architecture.elements.nodes.find(i => i.data.definition === 'Point')
              const newId = uuidv4()
              architecture.elements.nodes.push({
                data: {
                  ...point.data,
                  id: newId,
                  value: newId,
                  name: 'StructureDottedLine'
                }
              })
            }
            const putGraphName = `ugmJson/${taskId}_graph.json`
            await putDataToAil(putGraphName, architecture)
            let ugm = getUGM({ architecture })
            if (!ugm.boundingbox || !ugm.boundingbox.length) {
              ugm = getUGM({ architecture: ugm })
            }
            if (!ugm.boundingbox || !ugm.boundingbox.length) {
              try {
                fs.unlinkSync(oldPath)
              } catch (e) {
                console.log(e)
              }
              logRes({ res, res_code: -1, mes: 'boundingbox计算失败' })
            }
            ugm = addCurrentTimeToUGM(ugm)
            console.log(ugm.data.cols.point.find(p => p.name === 'StructureDottedLine'))
            const putName = `ugmJson/${taskId}.json`
            const putOriginName = `ugmJson/${taskId}_origin.json`
            await putDataToAil(putName, ugm)
            await putDataToAil(putOriginName, ugm)
            try {
              fs.unlinkSync(oldPath)
            } catch (e) {
              console.log(e)
            }
            logRes({ res, res_code: 0 })
          } catch (e) {
            try {
              fs.unlinkSync(oldPath)
            } catch (e) {
              console.log(e)
            }
            logRes({ res, res_code: -1, e })
          }
        } else {
          console.log('文件校验失败!!!')
          const oldPath = uploadFolder + req.file.filename
          try {
            fs.unlinkSync(oldPath)
          } catch (e) {
            console.log(e)
          }
          logRes({ res, res_code: -1 })
        }
      }
    })
  }
})

app.post('/save_data', async (req, res) => {
  // log(req)
  let { ugmId, data: newUGM, type } = req.body
  if (ugmId && newUGM && type) {
    if (!newUGM.data || (Array.isArray(newUGM.data) && !newUGM.data.length)) {
      newUGM = getUGM({ architecture: newUGM })
      if (!newUGM.data) {
        logRes({ res, res_code: -1, mes: '上传至阿里云失败' })
        return
      }
    }
    try {
      const putName = `ugmJson/${ugmId}.json`
      const isUGMExist = await isExist(client, putName)
      newUGM = addCurrentTimeToUGM(newUGM)
      console.log('isUGMExist', isUGMExist)
      if (!isUGMExist) {
        const originPutName = `ugmJson/${ugmId}_origin.json`
        await putDataToAil(originPutName, newUGM)
      }
      await putDataToAil(putName, newUGM)
      logRes({ res, res_code: 0 })
    } catch (e) {
      logRes({ res, res_code: -1, mes: '上传至阿里云失败', e })
    }
  } else {
    logRes({ res, res_code: -1, mes: '参数不正确' })
  }
})

/**
 *  BIMRemodeler读取数据使用
 */
app.post('/get_data', async (req, res) => {
  log(req)
  const { ugmId } = req.body
  try {
    const getName = `ugmJson/${ugmId}.json`
    let ugm = await getDataFromAil(getName)
    if (!ugm.boundingbox || !ugm.boundingbox.length) {
      ugm = getUGM({ architecture: ugm })
    }
    ugm = addCurrentTimeToUGM(ugm)
    res.send({ res_code: 0, ugm })
  } catch (e) {
    logRes({ res, res_code: -1, mes: '参数不正确' })
  }
})

app.post('/get_data_from_ail', async (req, res) => {
  log(req)
  const { url: getName, toBase64 = false } = req.body
  try {
    let result = null
    const type = getName.substring(0, 3)
    if (type === 'ugm') {
      let ugm = await getDataFromAil(getName)
      if (!ugm.boundingbox || !ugm.boundingbox.length) {
        ugm = getUGM({ architecture: ugm })
      }
      ugm = addCurrentTimeToUGM(ugm)
      logRes({ res, res_code: 0, [type]: ugm })
    } else {
      result = await getDataFromAil(getName)
      if (toBase64) {
        res.send({ res_code: 0, base64: result.content.toString('base64') })
      } else {
        res.send(result.content)
      }
    }
  } catch (e) {
    logRes({ res, res_code: -1, e })
  }
})

app.post('/put_pdf_to_ail', upload.single('pdf'), async function (req, res) {
  log(req)
  if (!req.file) {
    logRes({ res, res_code: -1 })
  } else {
    const { taskId } = req.body
    const pdfPath = uploadFolder + req.file.filename
    const putName = `pdf/${taskId}.pdf`
    try {
      await client.put(putName, path.normalize(pdfPath))
      try {
        fs.unlinkSync(pdfPath)
      } catch (e) {
        console.log(e)
      }
      logRes({ res, res_code: 0 })
    } catch (e) {
      try {
        fs.unlinkSync(pdfPath)
      } catch (e) {
        console.log(e)
      }
      logRes({ res, res_code: -1, e })
    }
  }
})

app.post('/put_dwg_to_ail', upload.single('dwg'), async function (req, res) {
  log(req)
  if (!req.file) {
    logRes({ res, res_code: -1 })
  } else {
    const { taskId } = req.body
    const dwgPath = uploadFolder + req.file.filename
    const putName = `dwg/${taskId}.dwg`
    try {
      await client.put(putName, path.normalize(dwgPath))
      try {
        fs.unlinkSync(dwgPath)
      } catch (e) {
        console.log(e)
      }
      logRes({ res, res_code: 0 })
    } catch (e) {
      try {
        fs.unlinkSync(dwgPath)
      } catch (e) {
        console.log(e)
      }
      logRes({ res, res_code: -1, e })
    }
  }
})

app.post('/put_ifc_to_ail', upload.single('ifc'), async function (req, res) {
  log(req)
  if (!req.file) {
    logRes({ res, res_code: -1 })
  } else {
    const { taskId } = req.body
    const ifcPath = uploadFolder + req.file.filename
    const putName = `ifc/${taskId}.ifc`
    try {
      await client.put(putName, path.normalize(ifcPath))
      try {
        fs.unlinkSync(ifcPath)
      } catch (e) {
        console.log(e)
      }
      logRes({ res, res_code: 0 })
    } catch (e) {
      try {
        fs.unlinkSync(ifcPath)
      } catch (e) {
        console.log(e)
      }
      logRes({ res, res_code: -1, e })
    }
  }
})

app.post('/put_ugm_to_ail', async (req, res) => {
  log(req)
  let { ugm, targetId } = req.body
  try {
    ugm = typeof ugm === 'string' ? JSON.parse(ugm) : ugm
    const putName = `ugmJson/${targetId}.json`
    await putDataToAil(putName, ugm)
    logRes({ res, res_code: 0 })
  } catch (e) {
    logRes({ res, res_code: -1, e })
  }
})

app.post('/put_data_to_ail', upload.single('data'), async (req, res) => {
  log(req)
  const { putName } = req.body
  const dataPath = uploadFolder + req.file.filename
  try {
    await client.put(putName, path.normalize(dataPath))
    try {
      fs.unlinkSync(dataPath)
    } catch (e) {
      console.log(e)
    }
    logRes({ res, res_code: 0 })
  } catch (e) {
    try {
      fs.unlinkSync(dataPath)
    } catch (e) {
      console.log(e)
    }
    logRes({ res, res_code: -1, e })
  }
})

async function isExist(client, name, options = {}) {
  try {
    await client.head(name, options)
    console.log('文件存在')
    return true
  } catch (e) {
    if (e.code === 'NoSuchKey') {
      console.log('文件不存在')
      return false
    }
  }
}

app.post('/clone_ugm', async (req, res) => {
  log(req)
  const { originId, targetId } = req.body
  const getName = `ugmJson/${originId}.json`
  try {
    const oldUGM = await getDataFromAil(getName)
    const path = `./upload/${originId}.json`
    fs.writeFileSync(path, JSON.stringify(oldUGM))
    const exec = require('child_process').exec
    const sh = `node cloneugm.js ${path}`
    exec(sh, async error => {
      if (!error) {
        try {
          const newUGM = JSON.parse(fs.readFileSync(path, 'utf-8'))
          const putName = `ugmJson/${targetId}.json`
          await putDataToAil(putName, newUGM)
          try {
            fs.unlinkSync(path)
          } catch (e) {
            console.log(e)
          }
          const options = {
            method: 'POST',
            url: 'https://api.mingdao.com/workflow/hooks/NjE2NGU5NGQwYTIyNTIxMDliZTA2NDc3',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              rowid: targetId,
              planResult: `ugmJson/${targetId}.json`
            })
          }
          request(options, function (error, response) {
            if (error) throw new Error(error)
            console.log(response.body)
          })
          logRes({ res, res_code: 0 })
        } catch (e) {
          try {
            fs.unlinkSync(path)
          } catch (e) {
            console.log(e)
          }
          logRes({ res, res_code: -1, e })
        }
      } else {
        try {
          fs.unlinkSync(path)
        } catch (e) {
          console.log(e)
        }
        logRes({ res, res_code: -1, e: error })
      }
    })
  } catch (e) {
    logRes({ res, res_code: -1, e })
  }
})

const divideRoom = ({ url, requestData, res }) =>
  new Promise((resolve, reject) => {
    request(
      {
        url: url,
        method: 'POST',
        json: true,
        headers: {
          'content-type': 'application/json'
        },
        body: requestData,
        timeout: 30 * 60 * 1000
      },
      function (e, response, body) {
        console.log('requestData', requestData)
        if (!e && response.statusCode === 200) {
          console.log('roomData', body.data.roomData)
          console.log('scanstation', body.data.scanstation)
          console.log('separators', body.data.separators)
          console.log('orientationAndDimension', body.data.orientationAndDimension)
          if (!body.data.scanstation || !body.data.scanstation) {
            console.log('自动规划报错', e, response, body)
            logRes({ res, res_code: -1, mes: '自动规划报错', e, body })
            reject()
          } else {
            resolve(body.data)
          }
        } else {
          logRes({ res, res_code: -1, mes: '自动规划报错', e, body })
          reject()
        }
      }
    )
  })

const planningScanstation = ({ url, requestData }) =>
  new Promise((resolve, reject) => {
    request(
      {
        url: url,
        method: 'POST',
        json: true,
        headers: {
          'content-type': 'application/json'
        },
        body: requestData
      },
      function (e, response, body) {
        console.log('requestData', requestData)
        if (!e && response.statusCode === 200) {
          console.log('uuidList', body.data.uuidList)
          if (!body.data.uuidList || body.data.uuidList.length === 0) {
            console.log('手动规划报错', e, response, body)
            resolve(null)
          } else {
            resolve(body.data)
          }
        } else {
          resolve(null)
        }
        reject()
      }
    )
  })

const getRegions = ({ url, requestData }) =>
  new Promise((resolve, reject) => {
    request(
      {
        url: url,
        method: 'POST',
        json: true,
        headers: {
          'content-type': 'application/json'
        },
        body: requestData
      },
      function (e, response, body) {
        console.log('requestData', requestData)
        if (!e && response.statusCode === 200) {
          console.log('regions', body.data.regions)
          if (!body.data.regions || body.data.regions.length === 0) {
            console.log('干湿分离报错', e, response, body)
            resolve(null)
          } else {
            resolve(body.data)
          }
        } else {
          resolve(null)
        }
        reject()
      }
    )
  })

const tsAnalyze = ({ url, requestData }) =>
  new Promise((resolve, reject) => {
    request(
      {
        url: url,
        method: 'POST',
        json: true,
        headers: {
          'content-type': 'application/json'
        },
        body: requestData
      },
      function (e, response, body) {
        console.log('requestData', requestData)
        if (!e && response.statusCode === 200) {
          console.log('output', body.data)
          // if (!body.data.regions || body.data.regions.length === 0) {
          //   console.log('干湿分离报错', e, response, body)
          //   resolve(null)
          // } else {
          //   resolve(body.data)
          // }
          resolve(body.data)
        } else {
          resolve(null)
        }
        reject()
      }
    )
  })

const deleteDir = path => {
  let files = []
  if (fs.existsSync(path)) {
    files = fs.readdirSync(path)
    files.forEach(file => {
      const currentPath = `${path}/${file}`
      if (fs.statSync(currentPath).isDirectory()) {
        deleteDir(currentPath)
      } else {
        fs.unlinkSync(currentPath)
      }
    })
  }
  fs.rmdirSync(path)
}

app.post('/node_divideRoom', async (req, res) => {
  log(req)
  const names = JSON.parse(fs.readFileSync('./roomNames.json', 'utf8'))
  if (req.body.type === 'new') {
    //用新算法计算
    try {
      const { taskId, planningId, stage, mergeList, isFromWeb } = req.body
      const ugmPath = path.join(__dirname, 'upload', `${taskId}.json`)
      const resultPath = path.join(__dirname, 'upload', `${taskId}_output.json`)
      const scanPath = path.join(__dirname, 'backend_sh', os.type() !== 'Linux' ? 'scan_plan.exe' : 'scan_plan')
      const getName = `ugmJson/${taskId}.json`
      const putName = `ugmJson/${planningId}.json`
      const exec = require('child_process').exec
      let oldUGM = await getDataFromAil(getName)
      if (!oldUGM.boundingbox || !oldUGM.boundingbox.length) {
        oldUGM = getUGM({ architecture: oldUGM })
      }
      oldUGM = addCurrentTimeToUGM(oldUGM)
      fs.writeFileSync(ugmPath, JSON.stringify(oldUGM))
      let sh
      if (os.type() === 'Linux') {
        sh = mergeList
          ? `chmod 777 ${scanPath} && ${scanPath} -t set -u ${ugmPath} -r ${JSON.stringify(mergeList[0])}`
          : `chmod 777 ${scanPath} && ${scanPath} -t plan -u ${ugmPath}`
      } else {
        sh = mergeList
          ? `${scanPath} -t=set -u=${ugmPath} -r=${JSON.stringify(mergeList[0])}`
          : `${scanPath} -t=plan -u=${ugmPath}`
      }
      console.log(sh)
      exec(sh, async error => {
        if (!error) {
          try {
            const result = JSON.parse(fs.readFileSync(resultPath, 'utf-8'))
            const instance = new Autoplan(oldUGM)
            const newUGM = mergeList ? instance.addApartment({ result }) : instance.new_autoplan({ result, stage })
            await putDataToAil(getName, newUGM)
            if (planningId && !isFromWeb) await putDataToAil(putName, newUGM)
            try {
              fs.unlinkSync(ugmPath)
              fs.unlinkSync(resultPath)
            } catch (e) {
              console.log(e)
            }
            logRes({ res, res_code: 0, ugm: isFromWeb ? newUGM : undefined })
          } catch (e) {
            try {
              fs.unlinkSync(ugmPath)
              fs.unlinkSync(resultPath)
            } catch (e) {
              console.log(e)
            }
            logRes({ res, res_code: -1, e })
          }
        } else {
          try {
            fs.unlinkSync(ugmPath)
            fs.unlinkSync(resultPath)
          } catch (e) {
            console.log(e)
          }
          logRes({ res, res_code: -1, e: error })
        }
      })
    } catch (e) {
      logRes({ res, res_code: -1, e })
    }
  } else {
    try {
      let { taskId, planningId, stage, mergeList, isFromWeb, deleteSeparator = false } = req.body
      stage = typeof stage === 'string' ? JSON.parse(stage) : stage
      const picklePath = `./pickle/${planningId}_Room.pickle`
      try {
        fs.accessSync(picklePath)
        console.log('存在pickle格式缓存')
        const type = 'ugm'
        const ugmPath = `./upload/${planningId}.json`
        const serverURL = 'http://47.98.108.253:5008'
        const getName = `ugmJson/${planningId}.json`
        let oldUGM = await getDataFromAil(getName)
        if (!oldUGM.boundingbox || !oldUGM.boundingbox.length) {
          oldUGM = getUGM({ architecture: oldUGM })
        }
        oldUGM = addCurrentTimeToUGM(oldUGM)
        fs.writeFileSync(ugmPath, JSON.stringify(oldUGM))
        const args = {
          url: serverURL + '/divide_room',
          requestData: { ugmId: planningId, type, stage, mergeList },
          res
        }
        const { roomData, scanstation, separators, orientationAndDimension } = await divideRoom(args)
        const { data, bim, elements } = oldUGM
        const instance = new Autoplan({ data, bim, elements, names })
        const newUGM = instance.autoplan({
          mergeList,
          stage,
          roomData,
          scanstation,
          separators,
          deleteSeparator,
          cb: () => {},
          orientationAndDimension
        })
        if (!isFromWeb) await putDataToAil(getName, newUGM)
        try {
          fs.unlinkSync(ugmPath)
        } catch (e) {
          console.log(e)
        }
        logRes({ res, res_code: 0, ugm: isFromWeb ? newUGM : undefined })
      } catch (e) {
        const type = 'ugm'
        const serverURL = 'http://47.98.108.253:5008'
        const getName = `ugmJson/${taskId}.json`
        const putName = `ugmJson/${planningId}.json`
        let oldUGM = await getDataFromAil(getName)
        if (!oldUGM.boundingbox || !oldUGM.boundingbox.length) {
          oldUGM = getUGM({ architecture: oldUGM })
        }
        oldUGM = addCurrentTimeToUGM(oldUGM)
        const ugmId = !planningId ? taskId : planningId
        const ugmPath = `./upload/${ugmId}.json`
        fs.writeFileSync(ugmPath, JSON.stringify(oldUGM))
        const args = {
          url: serverURL + '/divide_room',
          requestData: { ugmId, type, stage, mergeList },
          res
        }
        const { roomData, scanstation, separators, orientationAndDimension } = await divideRoom(args)
        const { data, bim, elements } = oldUGM
        const instance = new Autoplan({ data, bim, elements, names })
        const newUGM = instance.autoplan({
          mergeList,
          stage,
          roomData,
          scanstation,
          separators,
          deleteSeparator,
          cb: () => {},
          orientationAndDimension
        })
        await putDataToAil(getName, newUGM)
        if (planningId && !isFromWeb) await putDataToAil(putName, newUGM)
        try {
          fs.unlinkSync(ugmPath)
        } catch (e) {
          console.log(e)
        }
        logRes({ res, res_code: 0, ugm: isFromWeb ? newUGM : undefined })
      }
    } catch (e) {
      logRes({ res, res_code: -1, e })
    }
  }
})

app.post('/testData', async (req, res) => {
  const oldUGM = JSON.parse(fs.readFileSync('./drawinfo.json', 'utf8'))
  const { roomData, scanstation, separators, orientationAndDimension } = JSON.parse(
    fs.readFileSync('./drawinfo_divideRoom.json', 'utf8')
  )
  // res.send({ ...roomData })
  const { data, bim, elements } = oldUGM
  const instance = new Autoplan({ data, bim, elements })
  const newUGM = instance.autoplan({
    mergeList: [],
    stage: ['masonry', 'plaster'],
    roomData,
    scanstation,
    separators,
    deleteSeparator: false,
    orientationAndDimension,
    cb: () => {}
  })
  res.send({ ...newUGM })
})

app.post('/node_planningScanstation', async (req, res) => {
  log(req)
  if (req.body.type === 'new') {
    //用新算法计算
    try {
      let { ugmId: taskId, points, selectedIds, stage } = req.body
      stage = typeof stage === 'string' ? JSON.parse(stage) : stage
      const ugmPath = path.join(__dirname, 'upload', `${taskId}.json`)
      const resultPath = path.join(__dirname, 'upload', `${taskId}_output.json`)
      const scanPath = path.join(__dirname, 'backend_sh', os.type() !== 'Linux' ? 'scan_plan.exe' : 'scan_plan')
      const execSync = require('child_process').execSync
      const getName = `ugmJson/${taskId}.json`
      let oldUGM = await getDataFromAil(getName)
      if (!oldUGM.boundingbox || !oldUGM.boundingbox.length) {
        oldUGM = getUGM({ architecture: oldUGM })
      }
      oldUGM = addCurrentTimeToUGM(oldUGM)
      fs.writeFileSync(ugmPath, JSON.stringify(oldUGM))
      const { data, bim, elements } = oldUGM
      const instance = new Autoplan({ data, bim, elements })
      let sh
      for (let i = 0; i < points.length; i++) {
        const point = points[i]
        if (os.type() === 'Linux') {
          sh = `chmod 777 ${scanPath} && ${scanPath} -t add -u ${ugmPath} -c ${JSON.stringify(point)} -s ${stage[0]}`
        } else {
          sh = `${scanPath} -t=add -u=${ugmPath} -c=${JSON.stringify(point)} -s=${stage[0]}`
        }
        try {
          await execSync(sh)
          const result = JSON.parse(fs.readFileSync(resultPath, 'utf-8'))
          const { scan_walls: uuidList } = result
          instance.manualplan({ stage, uuidList, point, selectedIds, type: 'new' })
        } catch (e) {
          console.log(e)
        }
      }
      try {
        fs.unlinkSync(ugmPath)
        fs.unlinkSync(resultPath)
      } catch (e) {
        console.log(e)
      }
      const newUGM = getUGM({ data: instance.getData(), bim: instance.getBIM() })
      logRes({ res, res_code: 0, ugm: newUGM })
    } catch (e) {
      logRes({ res, res_code: -1, e })
    }
  } else {
    try {
      let { ugmId: taskId, points, selectedIds, stage } = req.body
      let originUgmId = ''
      const index = taskId.indexOf('_')
      if (index !== -1) {
        originUgmId = taskId.split('_')[0]
      } else {
        originUgmId = taskId
      }
      console.log(originUgmId)
      stage = typeof stage === 'string' ? JSON.parse(stage) : stage
      const type = 'ugm'
      const ugmPath = `./upload/${originUgmId}.json`
      const serverURL = 'http://47.98.108.253:5008'
      const getName = `ugmJson/${originUgmId}.json`
      let copyUGM = null
      if (originUgmId !== taskId) {
        const copyName = `ugmJson/${taskId}.json`
        copyUGM = await getDataFromAil(copyName)
      }

      // 规划用
      let oldUGM = await getDataFromAil(getName)
      if (!oldUGM.boundingbox || !oldUGM.boundingbox) {
        oldUGM = getUGM({ architecture: oldUGM })
      }
      oldUGM = addCurrentTimeToUGM(oldUGM)
      fs.writeFileSync(ugmPath, JSON.stringify(oldUGM))
      const promises = []
      points.forEach(point => {
        const args = {
          url: serverURL + '/planning_scanstation',
          requestData: { ugmId: originUgmId, type, point, stage, selectedIds }
        }
        promises.push(planningScanstation(args))
      })
      let instance = null
      if (originUgmId !== taskId) {
        const { data, bim, elements } = copyUGM
        instance = new Autoplan({ data, bim, elements })
      } else {
        const { data, bim, elements } = oldUGM
        instance = new Autoplan({ data, bim, elements })
      }

      Promise.all(promises)
        .then(data => {
          data.forEach((item, index) => {
            if (item && item.uuidList) {
              const { uuidList } = item
              const point = points[index]
              instance.manualplan({ stage, uuidList, point, selectedIds })
            }
          })
          const newUGM = getUGM({ data: instance.getData(), bim: instance.getBIM() })
          try {
            fs.unlinkSync(ugmPath)
          } catch (e) {
            console.log(e)
          }
          logRes({ res, res_code: 0, ugm: newUGM })
        })
        .catch(e => {
          logRes({ res, res_code: -1, e })
        })
    } catch (e) {
      logRes({ res, res_code: -1, e })
    }
  }
})

app.post('/node_getRegions', async (req, res) => {
  log(req)
  try {
    const { ugmId: taskId, inputData, roomInfos } = req.body
    const ugmPath = `./upload/${taskId}.json`
    const serverURL = 'http://47.98.108.253:5008'
    const getName = `ugmJson/${taskId}.json`
    let oldUGM = await getDataFromAil(getName)
    if (!oldUGM.boundingbox || !oldUGM.boundingbox) {
      oldUGM = getUGM({ architecture: oldUGM })
    }
    oldUGM = addCurrentTimeToUGM(oldUGM)
    fs.writeFileSync(ugmPath, JSON.stringify(oldUGM))

    const args = {
      url: serverURL + '/getRegions',
      requestData: { ugmId: taskId, inputData }
    }
    const result = await getRegions(args)

    const { data, bim, elements } = oldUGM
    const instance = new Autoplan({ data, bim, elements })
    let newUGM = null

    console.log(result)
    instance.divideRegions(result.regions, roomInfos)
    newUGM = getUGM({ data: instance.getData(), bim: instance.getBIM() })

    try {
      fs.unlinkSync(ugmPath)
    } catch (e) {
      console.log(e)
    }
    logRes({ res, res_code: 0, ugm: newUGM })
  } catch (e) {
    logRes({ res, res_code: -1, e })
  }
})


app.post('/node_buildModel', async (req, res) => {
  log(req)
  try {
    const { taskId: ugmId } = req.body
    const ugmPath = `./upload/${ugmId}.zip`
    const ugmFilesDir = `./upload/${ugmId}`
    const serverURL = 'http://47.98.108.253:5008'
    const getName = `designZip/${ugmId}.zip`
    const zipFlow = await getDataFromAil(getName)
    // console.log(zipFlow)
    fs.writeFileSync(ugmPath, zipFlow.content)

    const args = {
      url: serverURL + '/ts_analyze',
      requestData: { ugmId }
    }
    const result = await tsAnalyze(args)
    // const result = {
    //   objPath: '/BIMRemodeler/objs/2346952a-651b-4f3e-960a-83dfcae6da15_walls.obj'
    // }
    console.log(result)
    const { msg, objPath, resReview, jsonPath, xmlPath } = result

    let objPath_res = null
    let jsonPath_res = null
    let xmlPath_res = null

    if (objPath.length > 1) {
      // 上传模型到oss

      //  上传obj 
      const localPath_obj = objPath.split('/BIMRemodeler/')[1]
      const putName_obj = objPath.split('/BIMRemodeler/')[1]
      const uploadRes_obj = await client.put(putName_obj, path.normalize(localPath_obj))

      // 上传objJson
      const localPath_objson = jsonPath.split('/BIMRemodeler/')[1]
      const putName_objson = jsonPath.split('/BIMRemodeler/')[1]
      const uploadRes_objson = await client.put(putName_objson, path.normalize(localPath_objson))

      // 上传xml
      const localPath_xmlPath = xmlPath.split('/BIMRemodeler/')[1]
      const putName_xmlPath = xmlPath.split('/BIMRemodeler/')[1]
      const uploadRes_xmlPath = await client.put(putName_xmlPath, path.normalize(localPath_xmlPath))

      try {
        console.log(uploadRes_obj)
        const { status } = uploadRes_obj.res
        if (status === 200) {
          objPath_res = putName_obj
        }
        console.log(uploadRes_objson)
        const { status: status1 } = uploadRes_objson.res
        if (status1 === 200) {
          jsonPath_res = putName_objson
        }
        console.log(uploadRes_xmlPath)
        const { status: status2 } = uploadRes_xmlPath.res
        if (status2 === 200) {
          xmlPath_res = putName_xmlPath
        }
        // fs.unlinkSync(localPath)
      } catch (e) {
        console.log(e)
      }
    }

    try {
      fs.unlinkSync(ugmPath)

      deleteDir(ugmFilesDir)
    } catch (e) {
      console.log(e)
    }
    logRes({ res, res_code: 0, objPath: objPath_res, resReview: resReview, jsonPath: jsonPath_res, xmlPath: xmlPath_res, error: msg })
  } catch (e) {
    logRes({ res, res_code: -1, e })
  }
})

/**
 *  获取ifc数据
 */
app.post('/get_ifc_data', async (req, res) => {
  log(req)
  const { ifcId } = req.body
  try {
    const getName = `ifc/${ifcId}.ifc`
    await client.get(getName, `./dist/${ifcId}.ifc`)
    res.send({ res_code: 0 })
  } catch (e) {
    logRes({ res, res_code: -1, mes: '参数不正确' })
  }
})

app.post('/test', async (req, res) => {
  log(req)
  const ugmid = req.body.id
  console.log(ugmid)
  const ugmPath = `./upload/${ugmid}.json`
  const getName = `ugmJson/${ugmid}.json`
  const oldUGM = await getDataFromAil(getName)
  fs.writeFileSync(ugmPath, JSON.stringify(oldUGM))
  res.send({ res_code: ugmPath })
})

///获取本机ip///
function getIPAdress() {
  const interfaces = os.networkInterfaces()
  for (const devName in interfaces) {
    const iface = interfaces[devName]
    for (let i = 0; i < iface.length; i++) {
      const alias = iface[i]
      if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
        return alias.address
      }
    }
  }
}

const ip_address = getIPAdress()
const port = 3008
app.listen(port)

// const httpsServer = https.createServer(options, app)
// httpsServer.listen(port)

console.log('\x1b[36m%s\x1b[0m', `\nServer running at ${ip_address}:${port}`)
